package disco;

import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.SynchronousQueue;

public class CFQ implements Runnable {
    static int n2 = 0;
    
    LinkedList<proceso.Proceso> listaProcesos;  //Lista de todos los procesos
    CFQQueue cfqQueueAsin[];                    //Arreglo de todas las colas
                                                //asíncronas (RT, BE, Idle)
    
    Map cfqPriority;                            //Division por prioridades 
   
    
    CFQQueue activeQueue;                       //Cola activa
    
    
    int base_slice_asin;                        //time slice base de las colas
                                                //asíncronas
    int base_slice_sin;                         //time slice base de las colas
                                                //síncronas
    
    Map treeCFQRequest;                         //arbol de peticiones
    
    final int ASINCRONA = 2;                    //constantes usadas para
    final int SINCRONA = 1;                     //legibilidad del código
    
    static final int numPrioridades = 17;       //nùmero total de prioridades
                                                //posibles para los procesos
    static final int diferenciaSlice = 20;
    
    int numPistas;
    
    
    //proceso.ColaRequest colaRequest;
    SynchronousQueue<CFQRequest> sq; 
    /*
     * @base_slice_asin time slice base de las colas asíncronas
     * @base_slice_sin time slice base de las colas síncronas
     * @xmlParser el parser que ha evaluado el xml de entrada
     */
    static short NUMBER_ASYN =7;
    
    /*
     * Constructor
     */
    public CFQ(int base_slice_asin, int base_slice_sin,
            proceso.XMLParser xmlParser,
            SynchronousQueue<CFQRequest> sq) {
        this.base_slice_asin = base_slice_asin;
        this.base_slice_sin = base_slice_sin; 
        this.treeCFQRequest = Collections.synchronizedMap(new TreeMap());
        this.cfqPriority =  Collections.synchronizedMap(new HashMap());
        this.sq = sq;
        this.cfqQueueAsin = new CFQQueue[numPrioridades];
        this.numPistas = xmlParser.getNumPistas();
        for(int i = 0; i < numPrioridades; i++) {
            this.cfqQueueAsin[i] = new CFQQueue(i, base_slice_asin, xmlParser.getNumPistas());
            this.cfqPriority.put(i, Collections.synchronizedMap(new HashMap()));
        }
        new Thread(this, "CFQ").start();        
    }
    
    public void run() {
        int n = 0;
        while (true) {
            try {
                CFQRequest cfqRequest = sq.remove();
                n++;
//                System.out.println("CFQ recibe " +  n);
                //TODO quitar System.out.println("CFQ <-- dispatchPeticiones " + cfqRequest);
                llenarListasCFQQueue(cfqRequest);
                //System.out.println("Taken " + cfqRequest.toString());
            } catch (java.util.NoSuchElementException e) {
                //TODO manejar excepciòn
            }
        }
        
    }
    
    
    
    
    /**
     * Coloca cada CFQRequest en la lista que le corresponde para luego ser
     * despachada al disco
     */
    public void llenarListasCFQQueue(CFQRequest request) {
        if (request.tipo == ASINCRONA) {
            cfqQueueAsin[request.prioridad].put(request);   //Se inserta el
                                                            //request ordenadamente
        } else {
            insertRequestServiceTree(request);
        }
    }
    
    
    /**
     * Inserta el request en la cola correspondiente
     * @param request 
     */
    private void insertRequestServiceTree(CFQRequest request) {
        Map auxPriority;
        CFQQueue auxQueue;
        CFQQueue queue;        
        
        auxPriority = (Map) this.cfqPriority.get(request.prioridad); 
        
        
        //Se hace un get al Map para ver si hay una petición con el mismo id
        //que la actual
        auxQueue = (CFQQueue) auxPriority.get(request.pid);
        
        //Si no existe esa petición, quiere decir que no hay cola asociada a ese
        //proceso. Luego, se crea
        if (auxQueue == null) { 
            auxPriority.put(request.pid, new CFQQueue(request.prioridad,
                    base_slice_sin, numPistas));
        }
        
        //Se inserta el request en la cola
        queue = (CFQQueue) auxPriority.get(request.pid);
        queue.put(request);
    }
    
    public CFQQueue[] getCfqQueueAsin() {
        return cfqQueueAsin;
    }

    public Map getCfqQueueSin() {
        return cfqPriority;
    }
    
    
}
